defmodule SockWorkstation.SockCoopClient do
  use WebSockex

  # @token "coop-token"
  # @url "wss://72-j.cn:5179/xiaozhi/coop?token=#{@token}"
  # 保活间隔（30 秒）
  # @keepalive_interval 30_000
  @keepalive_ping 45_000
  # @sent_tts_start %{"type" => "tts", "state" => "start"}
  # @sent_tts_stop %{"type" => "tts", "state" => "stop"}
  # @sent_standby %{"type" => "tts", "state" => "standby"}

  # @sent_sentence_start %{"type" => "tts", "state" => "sentence_start","text" => "你好，我是小智。", "session_id" => "1150"}
  # @sent_sentence_stop %{"type" => "tts", "state" => "sentence_end"}

  # @sent_user_text %{"type" => "stt", "text" => "小智", "session_id" => "1150"}
  @name __MODULE__
  alias SockWorkstation.{
    CtrlMgrGen,
    CoopMgrGen,
    TTSHelperGen,
    ASRHelperGen,
    PcmEncoderGen,
    FrameHelperGen,
    # PingPongGen
    # SessionMgr
  }

  # 启动客户端
  def start_link(session_id) do
    IO.puts("Start coop client #{session_id}")
    rid = CtrlMgrGen.rot5(session_id)

    {:ok, _pid} =
      WebSockex.start_link(
        "wss://72-j.cn:5179/xiaozhi/coop?token=coop-#{rid}",
        @name,
        %{session_id: session_id},
        extra_headers: headers(rid)
      )

    # Process.link(pid)
    # {:ok, pid}
  end

  defp headers(rid) do
    [
      {"Authorization", "Bearer coop-#{rid}"}
      # {"X-DashScope-DataInspection", "enable"}
    ]
  end

  # 初始化回调
  @impl WebSockex
  def handle_connect(_conn, state) do
    # schedule_keepalive()
    schedule_ping()
    self_pid = self()

    send(self_pid, {:prep_coopcli, self_pid})
    # Process.send_after(self_pid, :first_coopcli, 1500)

    state =
      state
      |> Map.put(:self_pid, self_pid)
      |> Map.put(:coop_pid, nil)

    # |> Map.put(:chunk_size, 0)
    IO.puts("Cop Wss Connected! #{inspect(self_pid)}")
    {:ok, state}
  end

  # @impl WebSockex
  #   def handle_control({_text, [opcode: :ping]}, state) do
  #   {:reply, :ok, {:pong, ""}, state}
  # end

  # 发送文本消息
  def send_text(pid, message) do
    WebSockex.send_frame(pid, {:text, message})
  end

  # 发送二进制消息
  def send_binary(pid, binary_data) do
    WebSockex.send_frame(pid, {:binary, binary_data})
  end

  def send_speaking(pid) do
    sent_tts_start =
      # %{"type" => "tts", "state" => "start", "session_id" => session_id}
      %{"coop_cmd" => "tts_start"}
    WebSockex.send_frame(pid, {:text, sent_tts_start |> Jason.encode!()})
  end

  def send_listening(pid) do
    sent_tts_stop =
      # %{"type" => "tts", "state" => "stop", "session_id" => session_id}
      %{"coop_cmd" => "tts_stop"}
    WebSockex.send_frame(pid, {:text, sent_tts_stop |> Jason.encode!()})
  end

  def send_listened(pid) do
    sent_listened =
      # %{"type" => "tts", "state" => "islistened", "session_id" => session_id}
      %{"coop_cmd" => "listened"}
    WebSockex.send_frame(pid, {:text, sent_listened |> Jason.encode!()})
  end

  def send_not_listened(pid) do
    sent_not_listened =
      # %{"type" => "tts", "state" => "nolistened", "session_id" => session_id}
      %{"coop_cmd" => "not_listened"}

    WebSockex.send_frame(pid, {:text, sent_not_listened |> Jason.encode!()})
  end

  def send_start_intercom(pid, fr_sessid, to_sessid) do
    start_inter_com =
      # %{"type" => "vox", "state" => "start", "fr_sessid" => fr_sessid, "to_sessid" => to_sessid}
      %{"coop_cmd" => "vox_start_intercom", "fr_sessid" => fr_sessid, "to_sessid" => to_sessid}

    WebSockex.send_frame(pid, {:text, start_inter_com |> Jason.encode!()})
  end

  def send_stop_intercom(pid, fr_sessid, to_sessid) do
    stop_intercom =
      # %{"type" => "vox", "state" => "stop", "fr_sessid" => fr_sessid, "to_sessid" => to_sessid}
      %{"coop_cmd" => "vox_stop_intercom", "fr_sessid" => fr_sessid, "to_sessid" => to_sessid}

    WebSockex.send_frame(pid, {:text, stop_intercom |> Jason.encode!()})
  end

  def send_sentence_start(pid, text) do
    # sentence = %{
    #   "type" => "tts",
    #   "state" => "sentence_start",
    #   "text" => text,
    #   "session_id" => "1150"
    # }

    sentence = %{
      "coop_cmd" => "tts_sentence_start",
      "text" => text,

    }

    WebSockex.send_frame(pid, {:text, sentence |> Jason.encode!()})
  end

  def send_sentence_stop(pid) do
    # sent_sentence_stop = %{"type" => "tts", "state" => "sentence_end"}
    sent_sentence_stop = %{"coop_cmd" => "tts_sentence_end"}
    WebSockex.send_frame(pid, {:text, sent_sentence_stop |> Jason.encode!()})
  end

  def send_user_text(pid, text) do
    # map = %{"type" => "stt", "text" => text, "session_id" => "1150"}
    map = %{"coop_cmd" => "user_text", "text" => text}
    WebSockex.send_frame(pid, {:text, map |> Jason.encode!()})
  end

  def send_emtion_thinking(pid) do
    # map = %{"type" => "llm", "emotion" => "thinking", "session_id" => "1150"}
    map = %{"coop_cmd" => "emoji", "emotion" => "thinking"}
    WebSockex.send_frame(pid, {:text, map |> Jason.encode!()})
  end

  def send_goodbye(pid) do
    # sent_standby= %{"type" => "tts", "state" => "standby", "session_id" => session_id}
    sent_standby = %{"coop_cmd" => "tts_standby"}
    WebSockex.send_frame(pid, {:text, sent_standby |> Jason.encode!()})
  end

  def sendcmd_autolisten(pid) do
    # cmd = %{"type" => "ptt", "cmd" => "auto_listen"}
    cmd = %{"coop_cmd" => "auto_listen"}
    WebSockex.send_frame(pid, {:text, cmd |> Jason.encode!()})
  end

  def sendcmd_not_autolisten(pid) do
    # cmd = %{"type" => "ptt", "cmd" => "not_auto_listen"}
    cmd = %{"coop_cmd" => "not_auto_listen"}
    WebSockex.send_frame(pid, {:text, cmd |> Jason.encode!()})
  end

  def set_volume(pid, volume) do
    # 发送音量设置消息
    # msg = %{
    #   "type" => "iot",
    #   "commands" => [
    #     %{"name" => "Speaker", "method" => "SetVolume", "parameters" => %{"volume" => volume}}
    #   ]
    # }

    msg = %{"coop_cmd" => "speaker_setvolume", "volume" => volume}

    WebSockex.send_frame(pid, {:text, msg |> Jason.encode!()})
  end

  @impl WebSockex
  def handle_pong(:pong, state), do: {:ok, state}
  def handle_pong({:pong, _}, state), do: {:ok, state}
  # def handle_ping(_, state), do: {:ok, state}

  @impl WebSockex
  def handle_frame({:text, message}, state) do
    msg =
      message |> Jason.decode!()

    IO.puts("Coop Client Received text handle_frame: #{message}")

    case msg["event"] do
      "recv_opus" ->
        SockWorkstation.TTSHelperGen.test_opus(state.session_id)
        # SockWorkstation.PcmEncoderGen.pcm_to_opus(state.session_id, pcm_data)
        # {:reply, {:text, @sent_standby |> Jason.encode!()},state}
        {:ok, state}

      "recv_rm" ->
        IO.puts("Received rm message: #{message}")
        if File.exists?("peer.pcm"), do: File.rm("peer.pcm")
        {:ok, state}

      "standby" ->
        # IO.puts("Received standby message: #{message}")

        case msg["state"] do
          "speak" ->
            FrameHelperGen.stop_push(state.session_id)
            # Process.send_after(state.self_pid, :standby_speak, 120)
            # {:reply, {:text, @sent_tts_stop |> Jason.encode!()}, state}
            {:ok, state}

          # "listen" ->
          #   IO.puts("Received listen message: #{message}")
          #   SessionMgr.stop_session(state.session_id)
          #   {:ok, state}

          _ ->
            IO.puts("Received other standby message: #{message}")
            {:ok, state}
        end

      # {:ok, state}

      _ ->
        IO.puts("coop cli Received other text message: #{message}")

        {:ok, state}
    end
  end

  # 处理接收到的二进制消息
  def handle_frame({:binary, data}, state) do
    # IO.puts("Received coop client info bin: #{inspect(byte_size(data))}")
    # OpusDecoderGen.decode_opus_data(opus_data)
    # if byte_size(data) ==1, do: IO.inspect(data)
    # send(state.sent_pid, {:recv_opus, data})
    SockWorkstation.ASRHelperGen.frsent_opus(state.session_id, data)
    # {:ok, pcm_data} = SockWorkstation.OpusNif.decode_opus_data(data)

    {:ok, state}
  end

  @impl true

  def handle_info({:prep_coopcli, coop_pid}, state) do
    # Process.sleep(2000)
    # if is_nil(state.coop_pid) do
    sess_id = state.session_id
    CoopMgrGen.fetch_coop_pid(sess_id, coop_pid)
    TTSHelperGen.fetch_coop_pid(sess_id, coop_pid)
    ASRHelperGen.fetch_coop_pid(sess_id, coop_pid)
    PcmEncoderGen.fetch_coop_pid(sess_id, coop_pid)
    FrameHelperGen.fetch_coop_pid(sess_id, coop_pid)
    # PingPongGen.fetch_coop_pid(sess_id, coop_pid)

    # end
    {:ok, %{state | coop_pid: coop_pid}}
  end

  # def handle_info(:first_coopcli, state) do
  #   IO.puts("first_coopcli")
  #   CoopMgrGen.runfirst_for_uid(state.session_id, nil)

  # Process.sleep(120)
  # cli_mgr = CoopMgrGen.get_state(state.session_id)
  # # text = "你好，请尽快输入系统后台进行验证，你的验证码为。"
  # text = state.session_id

  # cond do
  #   !is_nil(cli_mgr.user_id) ->
  #     Process.send_after(
  #       cli_mgr.tts_helper_pid,
  #       {:bcast_tts,
  #        {"greet_authcode", "greet_authcode__#{state.session_id}__greet-#{state.session_id}", text}},
  #       200
  #     )

  #   true ->
  #     IO.puts("Cop Wss Connected for #{state.user_id}!")
  # end

  #   {:ok, state}
  # end
  # def handle_info(:standby_speak, state) do
  #   {:reply, {:text, @sent_tts_stop |> Jason.encode!()}, state}
  # end

  def handle_info({:tts_opus, opus_data}, state) do
    {:reply, {:binary, opus_data}, state}
  end

  def handle_info(:ping, state) do
    # IO.puts("coop sending ping")
    schedule_ping()
    # schedule_ping()
    {:reply, :ping, state}
  end

  def handle_info(:coopcli_stop, state) do
    # sess_id = state.session_id
    # FrameHelperGen.rm_coop_pid(sess_id)
    # PcmEncoderGen.rm_coop_pid(sess_id)
    # ASRHelperGen.rm_coop_pid(sess_id)
    # TTSHelperGen.rm_coop_pid(sess_id)
    # CoopMgrGen.rm_coop_pid(sess_id)
    # {:close, state}
    {:reply, {:text, "coocli_stop"}, state}

    # {:stop, :normal, state}
  end

  @impl true
  # 处理连接关闭
  def handle_disconnect(close_map, state) do
    IO.puts("WebSocket disconnected: #{inspect(close_map)}")
    {:reconnect, state}
  end

  @impl true
  def terminate(_reason, state) do
    # CoopMgrGen.rm_coop_pid()
    send(state.self_pid, :coopcli_stop)
    :ok
  end

  defp schedule_ping do
    # 每30秒发送一次心跳
    Process.send_after(self(), :ping, @keepalive_ping)
  end
end

# IO.puts("Coop client received recv_opus message")
# pcm_data = File.read!("by.16000.pcm")
# stream = File.stream!("by.16000.pcm", [:binary], 1920)
# Enum.each(stream, fn chunk ->
# {:ok, opus_data}=SockWorkstation.CodecNifGen.encode_pcm(state.session_id, chunk)
# # send(CoopMgrGen.get_state(state.session_id).tts_helper_pid, {:test_opus, opus_data})
# if byte_size(chunk) == 1920 do
#   Task.start(fn ->
#     SockWorkstation.TTSHelperGen.test_opus(state.session_id, opus_data)
#   end)
#   # SockWorkstation.TTSHelperGen.test_opus(state.session_id, opus_data)
# end

# end)

# "recv_broadcast" ->
#   IO.puts("Coop Client Received broadcast message: #{message}")
#   # coop_mgr = CoopMgrGen.get_state(state.session_id)

#   Process.sleep(4500)
#   send(CoopMgrGen.get_state(state.session_id).tts_helper_pid, {:bcast_tts, :authcode, msg["text"]})

#   {:ok, state}

# "userid_invalid" ->

# IO.puts("Received invalid message: #{message}")
# send(CoopMgrGen.get_state(state.session_id).coop_mgr_pid, :userid_invalid)
# Process.sleep(500)
# send(CoopMgrGen.get_state(state.session_id).tts_helper_pid, {:run_sent_tts, "你好，你的验证码为 1234"})
# Process.sleep(5000)
# send_goodbye(CoopMgrGen.get_state(state.session_id).coop_pid)
# TTSHelperGen.cast_sent_authcode(state.session_id,  "你好,你的验证码为 1234")
# Process.sleep(5000)
# {:reply, {:text, Jason.encode!(@sent_standby)}, state}
# {:ok, state}
# send_goodbye(state.self_pid)
# {:ok, state}

# Process.sleep(15_000)
# {:reply, :ok, {:text, @sent_standby |> Jason.encode!()}, state}

# {:ok, state}

# cli_mgr = CoopMgrGen.get_state(state.session_id)
# text= "你好，你的验证码为 #{state.session_id}，请尽快输入系统后台进行验证。"
# cond do
#   !is_nil(cli_mgr.user_id) ->
#     Process.send_after(
#       cli_mgr.tts_helper_pid,
#       {:bcast_tts, :authcode, text},
#       1200
#     )

#   true ->
#     IO.puts("Cop Wss Connected for #{state.user_id}!")
# end

# def handle_info(:send_keepalive, state) do
#   # 发送保活消息
#   send_text(self(), "keepalive")
#   schedule_ping()
#   # 重新启动保活定时器
#   schedule_keepalive()
#   {:ok, state}
# end

# Process.sleep(6000)
# SockCoopClient.send_goodbye(coop_mgr.coop_pid)
# Process.sleep(10000)
# {:reply, {:text, @sent_standby |> Jason.encode!()},state}
# 启动保活定时器
# defp schedule_keepalive do
#   Process.send_after(self(), :send_keepalive, @keepalive_interval)
# end

# def handle_info(:run_codec, state) do
#   # Process.sleep(2000)
#   # SockWorkstation.CoopHelperSup.start_opus_decode({state["session_id"], state["self_pid"]})
#   SockWorkstation.CoopHelperSup.start_pcm_encode({state.session_id, state.self_pid})
#   {:ok, state}
# end

# def handle_frame({:pong, _payload}, state) do
#   # 更新最后一次收到 Pong 的时间
#   IO.puts("Pong received")
#   # new_state = %{state | last_pong: System.monotonic_time()}
#   {:ok, state}
# end

# def handle_info({:tts_opus, opus}, state) do
#   # send_binary(state.coop_pid, opus)
#   # {:noreply, state}
#   {:reply, {:binary, opus}, state}

# end

# def handle_info(:run_nif_codec, state) do
#   # Process.sleep(2000)
#   SockWorkstation.CoopHelperSup.start_nif_codec(state["session_id"])

#   {:ok, state}
# end

# def handle_info(:run_sent_asr, state) do
#   # SockWorkstation.SockCoopClient.send_listening(state["self_pid"])
#   {:ok, asr_pid} =
#     SockWorkstation.CoopHelperSup.start_asr_client({state["session_id"], state["self_pid"]})

#   Process.sleep(80)
#   SockWorkstation.SockASRClient.send_run_task(asr_pid, UUID.uuid4())
#   {:ok, state}
# end

# def handle_info({:asr_result, result}, state) do
#   IO.puts("Received asr result: #{result}")

#   # SockWorkstation.SockASRClient.send_finish_task(CoopMgrGen.get_state().asr_pid, state["asr_task_id"])
#   # Process.send_after(CoopMgrGen.get_state().asr_pid, :close, 1000)
#   # SockWorkstation.SockCoopClient.sender_speaking(CoopMgrGen.get_state().coop_pid)

#   # SockWorkstation.SockTTSClient.run_tts(result)
#   {:ok, state}
# end

# defp via_tuple(session_id, type) do
#   {:via, Registry, {SockWorkstation.SessionRegistry, {session_id, type}}}
# end

# def handle_info({:asr_result, result}, state) do
# IO.puts("Received asr result: #{result}")
# SockWorkstation.SockASRClient.send_finish_task(CoopMgrGen.get_state().asr_pid, state["asr_task_id"])
# Process.send_after(CoopMgrGen.get_state().asr_pid, :close, 1000)
# SockWorkstation.SockCoopClient.sender_speaking(CoopMgrGen.get_state().coop_pid)

# SockWorkstation.SockTTSClient.run_tts(result)
#   {:ok, state}
# end

# def handle_info(:sender_listening, state) do
#       # SockWorkstation.CoopHelperSup.start_asr_client(
#       #   {CoopMgrGen.get_state(state["session_id"]).coop_pid, CoopMgrGen.get_state(state["session_id"]).session_id}
#       # )
#       # SockASRClient.send_run_task(
#       #   CoopMgrGen.get_state(state["session_id"]).asr_pid,
#       #   asr_task_id
#       # )
#       # send_text(state.self_pid, @sent_tts_stop |> Jason.encode!())
#   {:ok, state}
# end

# def handle_info({:pcm, pcm_data}, state) do

# {:ok, pcm_data} = SockWorkstation.OpusNif.decode_opus_data(data)
#  IO.puts("Received coop client info pcm: #{inspect(byte_size(pcm_data))}")
# File.write!("peer.pcm", pcm_data, [:append])

# SockASRClient.send_asr_task(CoopMgrGen.get_state(state["session_id"]).asr_pid, pcm_data)
# {:ok, state}
# end
#         SockASRClient.send_run_task(
#   CoopMgrGen.get_state(state["session_id"]).asr_pid,
#   UUID.uuid4(:hex)
# )
# send(CoopMgrGen.get_state(state["session_id"]).coop_mgr_pid, :sender_listening)
# {:ok, asr_pid} = SockWorkstation.CoopHelperSup.start_asr_client({state.session_id, state.coop_pid})
# Process.sleep(200)
# SockWorkstation.SockASRClient.send_run_task(asr_pid,  UUID.uuid4())
#  asr_task_id = UUID.uuid4(:hex)
# SockWorkstation.SockCoopClient.sender_speaking(CoopMgrGen.get_state(state["session_id"]).coop_pid)

# SockWorkstation.CoopHelperSup.start_asr_client(
#   {CoopMgrGen.get_state(state["session_id"]).session_id,CoopMgrGen.get_state(state["session_id"]).coop_pid}
# )
# SockASRClient.send_run_task(
#   CoopMgrGen.get_state(state["session_id"]).asr_pid,
#   UUID.uuid4(:hex)
# )
